package com.huawang.mdesign.model.service.inter;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huawang.business.command.CommandAddType;
import com.huawang.business.command.CommandParameter;
import com.huawang.business.command.ModelLimitService;
import com.huawang.business.command.definition.ICommand;
import com.huawang.business.command.executer.CommandExecutor;
import com.huawang.business.command.factory.CommandFactory;
import com.huawang.business.constants.*;
import com.huawang.business.data.fix.entity.ModelFixResult;
import com.huawang.business.data.share.core.IQueryShareService;
import com.huawang.business.data.share.entity.UseProject;
import com.huawang.business.data.state.ISaveStateService;
import com.huawang.business.dto.*;
import com.huawang.business.dto.project.ModelDependency;
import com.huawang.business.dto.project.Project;
import com.huawang.business.dto.project.ProjectConfig;
import com.huawang.business.entity.ReqIfDataInfo;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.cowork.ICoworkService;
import com.huawang.business.service.globalnumber.IInternalGlobalNumberService;
import com.huawang.business.service.init.InitializeService;
import com.huawang.business.service.judge.BusinessJudgeService;
import com.huawang.business.service.judge.OutSideTip;
import com.huawang.business.service.judge.TipService;
import com.huawang.business.service.model.ImportHandler;
import com.huawang.business.service.model.base.Cache.NamingRuleCache;
import com.huawang.business.service.model.base.ModelManagerConfig;
import com.huawang.business.service.model.base.UMLFacility;
import com.huawang.business.service.model.base.UmlService;
import com.huawang.business.service.model.core.InternalRequirementService;
import com.huawang.business.service.model.core.InternalUmlService;
import com.huawang.business.service.model.core.ModelPropertyInfoService;
import com.huawang.business.service.model.core.display.KeywordsCache;
import com.huawang.business.service.model.core.number.GlobalNumberCache;
import com.huawang.business.service.model.core.project.InternalProjectService;
import com.huawang.business.service.model.core.project.ProjectManager;
import com.huawang.business.service.model.parse.reqif.ReqIfPreviewVo;
import com.huawang.business.service.transaction.TransactionServiceImpl;
import com.huawang.business.util.InstanceVoUtils;
import com.huawang.business.util.ValidateDataUtil;
import com.huawang.business.vo.CopyInfoVo;
import com.huawang.business.vo.CopyResultVo;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRElement;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.definition.mof.instances.NumberingSeq;
import com.huawang.core.definition.mof.util.SnowflakeIdWorkerUtil;
import com.huawang.core.definition.sysml.data.DefinitionStoreRepository;
import com.huawang.core.semantics.constants.ModelCreatorType;
import com.huawang.core.semantics.entity.ExportOutsideElementInfo;
import com.huawang.core.semantics.entity.ExportOutsideElementResult;
import com.huawang.core.semantics.entity.persistence.ImportPackageResult;
import com.huawang.core.semantics.entity.persistence.ProfileChange;
import com.huawang.core.semantics.entity.persistence.ProfileConfig;
import com.huawang.core.semantics.entity.persistence.ProfileMessage;
import com.huawang.core.semantics.entity.persistence.variation.ModelVariationComparesDTO;
import com.huawang.core.semantics.entity.persistence.variation.MofModelVariation;
import com.huawang.core.semantics.entity.queryResult.UpdatePropertyNames;
import com.huawang.core.semantics.entity.transaction.ExecutingRecordResult;
import com.huawang.core.semantics.entity.transaction.LocalTransaction;
import com.huawang.core.semantics.exception.CommandException;
import com.huawang.core.semantics.exception.IsOutSideException;
import com.huawang.core.semantics.exception.LocalTransactionNotStartException;
import com.huawang.core.semantics.exception.TransactionNotExistingException;
import com.huawang.core.semantics.persistence.IPersistenceBaseService;
import com.huawang.core.semantics.utils.TransactionUtil;
import com.huawang.mdesign.model.service.constant.UAFProfileConstants;
import com.huawang.mdesign.model.service.dto.*;
import com.huawang.mdesign.model.service.facade.util.CustomizationModelService;
import com.huawang.mdesign.model.service.util.LogUtil;
import com.huawang.mdesign.model.service.util.ReadMd3Utils;
import com.huawang.mdesign.model.service.util.uaf.ProjectUtils;
import com.huawang.mdesign.model.service.vo.*;
import com.huawang.xmlImport.service.ExportService;
import com.huawang.xmlImport.vo.ExportXmiDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.huawang.business.constants.ModelActionName.*;
import static com.huawang.business.constants.ProfileConstants.DEFAULT_PROFILE;
import static com.huawang.business.service.model.core.project.ProjectManager.DATABASE;
import static com.huawang.business.service.model.core.project.ProjectManager.MD3;

@Service
@Primary
@Slf4j
public class ProjectService {

    @Autowired
    private TransactionServiceImpl transactionService;

    @Autowired
    private InternalUmlService internalUmlService;

    @Autowired
    private BusinessJudgeService businessJudgeService;

    @Autowired
    private InternalProjectService internalProjectService;

    @Autowired
    private InternalRequirementService internalRequirementService;

    @Autowired
    private CustomizationModelService customizationModelService;

    @Autowired
    private ModelManagerConfig managerConfig;

    @Autowired
    private ProfileService profileService;

    @Autowired
    private IPersistenceBaseService persistenceBaseService;

    @Autowired
    private ISaveStateService iSaveStateService;

    @Autowired
    private ICoworkService coworkService;

    @Autowired
    private UMLFacility umlFacility;

    @Autowired
    private CommandExecutor commandExecutor;

    @Autowired
    private IQueryShareService queryShareService;

    @Autowired
    @Lazy()
    private ExportService exportService;

    @Autowired
    private InitializeService initializeService;

    @Autowired
    private ModelPropertyInfoService modelPropertyInfoService;

    @Autowired
    private GlobalNumberCache globalNumberCache;

    @Autowired
    private NamingRuleCache namingRuleCache;

    private final UmlService umlService;
    private final ProjectManager projectManager;
    private final ImportHandler importHandler;

    @Autowired
    private TipService tipService;

    @Autowired
    private IInternalGlobalNumberService internalGlobalNumberService;

    @Autowired
    private ModelLimitService modelLimitService;

    public ProjectService(
            final UmlService umlService,
            final ProjectManager projectManager,
            final ImportHandler handler) {
        this.umlService = umlService;
        this.projectManager = projectManager;
        this.importHandler = handler;
    }

    @NotNull
    public Project create(final @NotNull ProjectDTO dto) {
        LogUtil.printSerializeOnlineLogs("create -> dto: ", dto);
        ProjectCreateDTO createDto = new ProjectCreateDTO();
        createDto.setProjectId(dto.getProjectId());
        createDto.setProjectType(ProjectTypeEnum.MODEL.value());
        createDto.setProfileLibPath(dto.getProfileLibPath());
        createDto.setProjectSpecification(dto.getSpecification());
        createDto.setDefaultSaveDir(Objects.isNull(dto.getDefaultSaveDir()) ? System.getProperty("user.dir") : dto.getDefaultSaveDir());
        if (dto.getDependencies() != null) {
            createDto.setCustomizationProfiles(dto.getDependencies());
        }

        return create(createDto);
    }

    @NotNull
    public Project create(final @NotNull ProjectCreateDTO dto) {
        LogUtil.printSerializeOnlineLogs("create -> dto: ", dto);
        ValidateDataUtil.isNotNull(dto.getDefaultSaveDir(), ErrorCode.DEFAULT_DIR_NULL);
        final String projectId = dto.getProjectId();
        List<String> oldDefaultProfile = new ArrayList<>(DEFAULT_PROFILE);
        Project project = projectManager.getProject(projectId);
        if (project != null) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_REPEAT);
        }
        try {
            project = projectManager.createAndActive(projectId, dto.getDefaultSaveDir(), dto.getProjectSpecification());
            if (StringUtils.isNotEmpty(dto.getProjectType())) {
                project.setProjectType(dto.getProjectType());
            }

            if (StringUtils.isNotEmpty(dto.getProjectSpecification())) {
                project.setProjectSpecification(dto.getProjectSpecification());
            }
            ProjectUtils.updateProfileByProjectSpecification(project.getProjectSpecification());
            final List<ModelDependency> initProfile = DEFAULT_PROFILE.stream().map(it ->
                    new ModelDependency(it, 1L)).collect(Collectors.toList());

            final List<ModelDependency> customizeProfiles = dto.getCustomizationProfiles();
            Set<String> profileIds = new HashSet<>(DEFAULT_PROFILE);
            List<ModelDependency> dependencies;
            this.internalProjectService.setGlobalWriteableState(projectId, true);
            if (CollectionUtils.isNotEmpty(customizeProfiles)) {
                dependencies = new ArrayList<>(CollectionUtils.union(initProfile, customizeProfiles));
                profileIds.addAll(initProfileDependency(dependencies, dto.getProfileLibPath(), initProfile,
                        dto.getProfileLibPath(), project));
            } else {
                dependencies = initProfile;
            }

            project.setDependencies(dependencies);
            final MetaClassInstance rootModel = createRootModel(project);
            projectManager.flushDb(projectId);
            project.setRootModel(rootModel.getId());
            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            this.iSaveStateService.setIsCoWork(projectId, true);
            internalProjectService.setProfileOwner(project, rootModel, new HashSet<>(profileIds));
            this.iSaveStateService.setIsLoggingVariation(projectId, true);
            this.customizationModelService.initCustomization(projectId);
        } catch (Exception e) {
            log.error("新增项目失败", e);
            ProjectUtils.rollBackDefaultProfile(oldDefaultProfile);
        } finally {
            this.internalProjectService.setGlobalWriteableState(projectId, false);
            // 缓存项目中的编号属性
            globalNumberCache.putNumberProperties(projectId);
            // 清除命名规则缓存
            namingRuleCache.putNamingRuleMap(projectId);
        }
        if (project == null) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_CREATE_ERROR);
        }
        return project;
    }

    @NotNull
    public MetaClassInstance createRootModel(Project project) {
        LogUtil.printSerializeOnlineLogs("project: ", project);
        if (com.huawang.mdesign.model.service.constant.ProjectSpecificationEnum.SYSMML.value().equals(project.getProjectSpecification())) {
            return createSysMLRootModel(project);
        } else {
            return createUAFRootModel(project);
        }
    }

    /**
     * 创建SysML项目的根元素
     *
     * @param project
     * @return
     */
    private MetaClassInstance createSysMLRootModel(Project project) {
        String name = "模型";
        if (StringUtils.equals(project.getProjectType(), "modelLibrary")) {
            name = "模型库";
        }
        if (Objects.equals(Locale.US, LocaleContextHolder.getLocale())) {
            name = "Model";
        }

        CommandParameter rootModelParameter = CommandParameter.builder()
                .type(CommandAddType.MODEL)
                .typeId(UMLDefinitionConstants.Model)
                .instanceId(ModelConstantURI.initInstanceId())
                .projectId(project.getId())
                .defaultName(name)
                .build();

        if (Objects.equals(ProjectTypeEnum.MODEL_LIBRARY.value(), project.getProjectType())) {
            rootModelParameter.setApplyStereotypes(Collections.singletonList(UMLDefinitionConstants.Customization_ModelLibrary));
        }

        return umlService.addModel(rootModelParameter);
    }

    /**
     * 创建UAF项目的根元素
     *
     * @param project
     * @return
     */
    private MetaClassInstance createUAFRootModel(Project project) {
        LogUtil.printSerializeOnlineLogs("project: ", project);
        List<String> appliedStereotypes = new ArrayList<>(2);
        appliedStereotypes.add(UMLDefinitionConstants.UAF_ArchitecturalDescription);

        String name = "模型";
        if (StringUtils.equals(project.getProjectType(), "modelLibrary")) {
            name = "模型库";
            appliedStereotypes.add(UMLDefinitionConstants.Customization_ModelLibrary);
        }
        if (Objects.equals(Locale.US, LocaleContextHolder.getLocale())) {
            name = "Model";
        }

        CommandParameter rootModelParameter = CommandParameter.builder()
                .type(CommandAddType.MODEL)
                .typeId(UMLDefinitionConstants.Package)
                .instanceId(ModelConstantURI.initInstanceId())
                .applyStereotypes(appliedStereotypes)
                .projectId(project.getId())
                .defaultName(name)
                .build();

        return umlService.addModel(rootModelParameter);
    }

    @NotNull
    public Boolean delete(@NotNull String projectId) {
        LogUtil.printOnlineLogs("delete -> projectId: ", projectId);
        // 项目关闭时清除部分缓存
        List<String> customizationKey = managerConfig.getPropertyConfigs().keySet().stream().filter(StringUtils::isNumeric).collect(Collectors.toList());
        customizationKey.forEach(key -> managerConfig.getPropertyConfigs().remove(key));
        return projectManager.clear(projectId, MD3);
    }

    /**
     * 项目关闭
     *
     * @param projectId
     * @param saveWay
     * @return java.lang.Boolean
     * @author baibf
     * @date 2023/06/05 15:03
     */
    @NotNull
    public Boolean delete(@NotNull String projectId, @NotNull String saveWay) {
        LogUtil.printOnlineLogs("projectId: {}, saveWay: {}", projectId, saveWay);
        // 项目关闭时清除部分缓存
        List<String> customizationKey = managerConfig.getPropertyConfigs().keySet().stream().filter(StringUtils::isNumeric).collect(Collectors.toList());
        customizationKey.forEach(key -> managerConfig.getPropertyConfigs().remove(key));
        // 清除全局编号配置缓存
        globalNumberCache.removeNumberPropertyWithAutoNumbersMap(projectId);
        // 清除命名规则缓存
        namingRuleCache.removeNamingRuleMap(projectId);
        return projectManager.clear(projectId, saveWay);
    }

    public Project openMd3(@NotNull ProjectOpenDTO md3Dto) {
        LogUtil.printOnlineLogs("md3Dto: ", md3Dto);
        ProjectDTO projectDto = makeProjectDto(md3Dto);
        if (BooleanUtils.isTrue(md3Dto.getIsReconnect())) {
            return reconnect(projectDto);
        }

        if (!ProjectDataTypeEnum.DB.value().equals(projectDto.getDataType())) {
            return openByJson(projectDto);
        }
        //打开的时候db连接存在未关闭的情况，需要删掉再打开
        return openByDb(projectDto);
    }

    /**
     * 解析md3文件
     *
     * @param md3Dto
     * @return com.huawang.mdesign.model.service.dto.ProjectDto
     * @author xz
     * @date 2023/05/25 09:33
     */
    @NotNull
    public ProjectDTO makeProjectDto(@NotNull ProjectOpenDTO md3Dto) {
        LogUtil.printOnlineLogs("md3Dto: ", md3Dto);
        if (Files.notExists(Paths.get(md3Dto.getFilePath()))) {
            log.error("项目路径:{}", md3Dto.getFilePath());
            throw AbortExecutionException.build(ErrorCode.FILE_URL_NOT_EXIST);
        }

        ProjectDTO projectDto = ReadMd3Utils.unZipToProject(md3Dto.getFilePath());
        projectDto.setProfileLibPath(md3Dto.getProfileLibPath());
        projectDto.setOnlineProfileLibPath(md3Dto.getOnlineProfileLibPath());
        projectDto.setFilePath(md3Dto.getFilePath());
        projectDto.setSaveWay(md3Dto.getSaveWay());
        projectDto.setDefaultSaveDir(md3Dto.getDefaultSaveDir());
        projectDto.setDbDir(md3Dto.getDbDir());
        ProjectConfigDTO config = ReadMd3Utils.unZipToConfig(md3Dto.getFilePath());
        projectDto.setOnline(config.getOnline());
        projectDto.setDependencies(config.getDependencies());
        projectDto.setProjectId(config.getId());
        projectDto.setName(config.getName());
        projectDto.setProjectVersion(config.getVersion());
        if (config.getProjectVersion() != null) {
            projectDto.setVersion(config.getProjectVersion());
        }
        projectDto.setSpecification(config.getProjectSpecification() == null ?
                com.huawang.mdesign.model.service.constant.ProjectSpecificationEnum.SYSMML.value() : config.getProjectSpecification());
        if (md3Dto.getDataSourceId() != null) {
            projectDto.setDataSourceId(md3Dto.getDataSourceId());
        }

        return projectDto;
    }

    /**
     * 打开内存版项目
     *
     * @param projectDto
     * @return com.huawang.mdesign.model.service.model.project.Project
     * @author xz
     * @date 2023/05/25 09:30
     */
    @Nullable
    public Project openByJson(@NotNull ProjectDTO projectDto) {
        LogUtil.printOnlineLogs("openByJson -> projectDto: ", projectDto);
        final String projectId = projectDto.getProjectId();
        final String rootId = projectDto.getRootModel();
        ValidateDataUtil.isNotNull(rootId);
        String currentId = SnowflakeIdWorkerUtil.getId();
        Project project = projectManager.createAndActive(projectId, projectDto.getDependencies(), currentId,
                projectDto.getDefaultSaveDir());
        project.setProfileLibPath(projectDto.getProfileLibPath());
        if (projectDto.isOnline()) {
            this.iSaveStateService.setIsLoggingVariation(projectId, false);
        }
        project.setOnline(projectDto.isOnline());
        project.setExport(projectDto.isExport());
        if (project.getRootModel() == null) {
            project.setRootModel(rootId);
        }
        try {
            final List<ModelDependency> initProfile = DEFAULT_PROFILE.stream().map(it ->
                    new ModelDependency(it, 1L)).collect(Collectors.toList());

            this.internalProjectService.setGlobalWriteableState(projectId, true);
            Set<String> profileIds = initProfileDependency(projectDto.getDependencies(), projectDto.getProfileLibPath(),
                    initProfile, projectDto.getProfileLibPath(), project);
            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            final MetaClassInstance rootModel;
            if (project.isExport()) {
                rootModel = createRootModel(project);
                project.setRootModel(rootModel.getId());
                persistenceBaseService.importPackagesFromJsonStringTo(projectId, projectDto.getModelData(),
                        new ArrayList<>(), new HashMap<>(),
                        rootModel.getId(), ModelCreatorType.CREATE_INTERACTIVE.getCreator());
            } else {
                project.setRootModel(rootId);
                persistenceBaseService.deserializeUMLFacilityFromMd3File(projectId, projectDto.getFilePath());
                rootModel = internalUmlService.fetchInstance(rootId, projectId);
            }

            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            profileIds.addAll(DEFAULT_PROFILE);

            internalProjectService.setProfileOwner(project, rootModel, profileIds);
            if (project.isOnline()) {
                internalProjectService.importVariation(projectId, projectDto.getFilePath());
                this.iSaveStateService.setIsCoWork(projectId, true);
                coworkService.updateAllPackageIsReadOnlyOrNot(projectId, true);
                this.iSaveStateService.setIsLoggingVariation(projectId, true);
            }
            this.customizationModelService.initCustomization(projectId);
        } catch (Exception e) {
            projectManager.clear(projectId, projectDto.getSaveWay());
            throw AbortExecutionException.build(ErrorCode.PROJECT_OPEN_ERROR, e);
        } finally {
            this.internalProjectService.setGlobalWriteableState(projectId, false);
        }

        return project;
    }

    /**
     * 打开数据库版项目
     *
     * @param projectDto
     * @return com.huawang.mdesign.model.service.model.project.Project
     * @author xz
     * @date 2023/05/25 09:34
     */
    @Nullable
    public Project openByDb(@NotNull ProjectDTO projectDto) {
        LogUtil.printSerializeOnlineLogs("openByDb -> projectDto: ", projectDto);
        long t1 = System.currentTimeMillis();
        final String projectId = projectDto.getProjectId();
        final String rootId = projectDto.getRootModel();
        ValidateDataUtil.isNotNull(projectDto.getDefaultSaveDir(), ErrorCode.DEFAULT_SAVE_FILE_NOT_EXIST_ERROR);
        String currentId = SnowflakeIdWorkerUtil.getId();
        Project project;
        if (StringUtils.equals(DATABASE, projectDto.getSaveWay())) {
            project = projectManager.getProject(projectId);
            if (project == null) {
                if (StringUtils.isEmpty(projectDto.getDbDir())) {
                    throw AbortExecutionException.build(ErrorCode.DB_DIR_ERROR);
                }

                // 不再重新去创建DB，直接连接原DB+
                project = projectManager.reconnectAndActive(projectId, projectDto.getDbDir(),
                        projectDto.getDefaultSaveDir(), projectDto.getDependencies(), projectDto.getSpecification());
                long t2 = System.currentTimeMillis();
                log.warn("openByDb reconnectAndActive times: {}", t2 - t1);
            }
        } else {
            projectManager.extractDb(projectDto.getFilePath(), currentId + "_" + projectId, projectDto.getDefaultSaveDir());
            project = projectManager.createAndActive(projectId, projectDto.getDependencies(), currentId,
                    projectDto.getDefaultSaveDir(), projectDto.getProjectVersion(), projectDto.getSpecification());
            long t2 = System.currentTimeMillis();
            log.warn("openByDb reconnectAndActive times: {}", t2 - t1);
        }

        project.setExport(projectDto.isExport());
        project.setProjectSpecification(projectDto.getSpecification());
        project.setOnline(projectDto.isOnline());
        project.setRootModel(rootId);
        project.setVersion(projectDto.getVersion());
        project.setName(projectDto.getName());
        project.setPath(projectDto.getFilePath());
        List<String> oldDefaultProfile = new ArrayList<>(DEFAULT_PROFILE);
        ProjectUtils.updateProfileByProjectSpecification(project.getProjectSpecification());
        try {
            this.internalProjectService.setGlobalWriteableState(projectId, true);
            this.internalProjectService.setIsThrowError(projectId, false);
            final List<ModelDependency> initProfile = DEFAULT_PROFILE.stream().map(it ->
                    new ModelDependency(it, 1L)).collect(Collectors.toList());

            Set<String> profileIds;
            long t2 = System.currentTimeMillis();
            if (project.isOnline()) {
                profileIds = initProfileDependency(projectDto.getDependencies(), projectDto.getOnlineProfileLibPath(),
                        initProfile, projectDto.getProfileLibPath(), project);
            } else {
                profileIds = initProfileDependency(projectDto.getDependencies(), projectDto.getProfileLibPath(),
                        initProfile, projectDto.getProfileLibPath(), project);
            }
            long t3 = System.currentTimeMillis();
            log.warn("openByDb initProfileDependency times: {}", t3 - t2);
            // initProfileDependency会关闭全局可写,此处再次开启
            this.internalProjectService.setGlobalWriteableState(projectId, true);
            profileIds.addAll(initProfile.stream().map(ModelDependency::getProfileName).collect(Collectors.toList()));
            MetaClassInstance rootModel;
            //导出类型时
            if (project.isExport()) {
                rootModel = internalUmlService.fetchInstance(rootId, projectId);
                if (rootModel == null) {
                    rootModel = createRootModel(project);
                }
                project.setRootModel(rootModel.getId());
                if (internalUmlService.fetchInstance(UMLDefinitionConstants.Package, projectId) == null) {
                    String defaultDbPath = ProjectManager.copyDefaultDb(project);
                    //需要将系统内置数据插入到当前数据库中
                    persistenceBaseService.importSystemDbDataToCurrentDb(projectId, defaultDbPath);
                    Files.deleteIfExists(Paths.get(defaultDbPath));
                }
            } else {
                project.setRootModel(rootId);
                rootModel = internalUmlService.fetchInstance(rootId, projectId);
            }

            //重新加载缓存
            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            long t4 = System.currentTimeMillis();
            log.warn("openByDb initialize times: {}", t4 - t3);
            // 项目另存为，如果有使用项目，更新之
            String saveAsBeforeProjectId = ProjectShareService.saveAsProjectMap.get(projectId);
            if (StringUtils.isNotEmpty(saveAsBeforeProjectId)) {
                ICommand updateUseProjectCommand = CommandFactory.createUpdateUseProjectCommand(saveAsBeforeProjectId,
                        null, null, null, null, projectId, null);
                commandExecutor.executes(projectId, Stream.of(updateUseProjectCommand).collect(Collectors.toList()));
            }

            //重新加载keywords缓存
            KeywordsCache.putKeywordsMap(projectId, profileService.getStereotypeKeywordsMap(projectId));
            long t5 = System.currentTimeMillis();
            log.warn("openByDb putKeywordsMap times: {}", t5 - t4);

            // 缓存项目中的编号属性
            globalNumberCache.putNumberProperties(projectId);
            // 清除命名规则缓存
            namingRuleCache.putNamingRuleMap(projectId);

            internalProjectService.setProfileOwner(project, rootModel, profileIds);
            this.iSaveStateService.setIsLoggingVariation(projectId, true);
            if (project.isOnline()) {
                this.iSaveStateService.setIsCoWork(projectId, true);

                long t6 = System.currentTimeMillis();
                coworkService.updateAllPackageIsReadOnlyOrNot(projectId, true);
                long t7 = System.currentTimeMillis();
                log.warn("openByDb updateAllPackageIsReadOnlyOrNot times: {}", t7 - t6);
            } else {
                persistenceBaseService.clearVariationData(projectId);
            }
            //2024.10.25初次打开项目更新numbering_seq表数据，如果只有默认的一条数据，则更新编号相关数据
            // && numberingSeqs.get(0).getAutoNumberProperty().equals("81193378961017472")
            List<NumberingSeq> numberingSeqs = this.internalGlobalNumberService.queryAllNumberSeq(projectId);
            if (numberingSeqs.size() == 1) {
                this.internalGlobalNumberService.modifyAllNumbering(projectId);
            }
            this.customizationModelService.initCustomization(projectId);
        } catch (Exception e) {
            ProjectUtils.rollBackDefaultProfile(oldDefaultProfile);
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        } finally {
            this.internalProjectService.setIsThrowError(projectId, true);
            this.internalProjectService.setGlobalWriteableState(projectId, false);
        }
        return project;
    }


    /**
     * 查询项目中的编号属性
     *
     * @param projectId
     * @return java.util.List<java.lang.String>
     * @author baibf
     * @date 2024/01/05 15:11
     */
    public List<String> queryNumberPropertyList(String projectId) {
        List<MetaClassInstance> autoNumberList = internalUmlService.querySpecifiedInstanceList(projectId,
                UMLDefinitionConstants.Customization_AutoNumber);
        if (CollectionUtils.isEmpty(autoNumberList)) {
            return Collections.emptyList();
        }
        List<ModelPropertyInfo> modelPropertyInfoList = modelPropertyInfoService.createModelPropertyInfoList(projectId,
                autoNumberList,
                Stream.of(UMLDefinitionConstants.Customization_AutoNumber_numberedProperty).collect(Collectors.toList()));

        List<MetaClassInstance> numberedPropertyList = modelPropertyInfoList.stream().map(modelPropertyInfo ->
                modelPropertyInfo.queryInstanceValue(UMLDefinitionConstants.Customization_AutoNumber_numberedProperty)).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(numberedPropertyList)) {
            return Collections.emptyList();
        }

        return numberedPropertyList.stream().map(BasicRElement::getId).collect(Collectors.toList());
    }

    /**
     * 重新连接到临时项目文件
     *
     * @param projectDto
     * @return com.huawang.mdesign.model.service.model.project.Project
     * @author xz
     * @date 2023/05/25 09:27
     */
    @Nullable
    public Project reconnect(@NotNull ProjectDTO projectDto) {
        LogUtil.printSerializeOnlineLogs("reconnect -> projectDto: ", projectDto);
        final String projectId = projectDto.getProjectId();
        final String rootId = projectDto.getRootModel();
        ValidateDataUtil.isNotNull(rootId);
        Project project = projectManager.getProject(projectId);
        if (project != null) {
            return project;
        }

        if (StringUtils.isEmpty(projectDto.getDefaultSaveDir())) {
            throw AbortExecutionException.build(ErrorCode.DB_DIR_ERROR);
        }

        project = projectManager.reconnectAndActive(projectId, projectDto.getDbDir(), projectDto.getDefaultSaveDir(),
                projectDto.getDependencies(), projectDto.getSpecification());
        project.setExport(projectDto.isExport());
        project.setOnline(projectDto.isOnline());
        project.setRootModel(rootId);
        project.setVersion(projectDto.getVersion());
        try {
            project.setRootModel(rootId);
            //重新加载缓存
            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            this.iSaveStateService.setIsLoggingVariation(projectId, true);
            this.iSaveStateService.setIsCoWork(projectId, true);
            globalNumberCache.putNumberProperties(projectId);
            // 清除命名规则缓存
            namingRuleCache.putNamingRuleMap(projectId);
        } catch (Exception e) {
            projectManager.clear(projectId, projectDto.getSaveWay());
            throw AbortExecutionException.build(ErrorCode.PROJECT_OPEN_ERROR, e);
        }

        return project;
    }

    public void loadPrivateData(String projectId, String projectSpecification) {
        LogUtil.printOnlineLogs("loadPrivateData -> projectId: ", projectId);
        //进行加载 主要为了ownerTree生成，确保getChildrenCascade获取有数据
        this.initializeService.initialize(projectId, false, true, true, projectSpecification);
    }

    private static String getProfileFilePath(String basePath, String profileName, Long profileVersion) {
        LogUtil.printOnlineLogs("basePath: {}, profileName: {}, profileVersion: {}", basePath, profileName, profileVersion);
        return basePath + File.separator + profileName + "(#" + profileVersion + ").md3p";
    }

    @NotNull
    private Set<String> initProfile(Project project, List<ProfileConfigVo> finalDep) {
        LogUtil.printSerializeOnlineLogs("project: {}, finalDep: {}", project, finalDep);
        Map<String, ProfileConfig> profileConfigMap =
                internalUmlService.getProjectConfigmap(project.getId());
        finalDep = finalDep.stream().filter(it -> {
            ProfileConfig config = profileConfigMap.get(it.getRootModel());
            //判断该拓展包数据是否已存在db中，以及version是否与db内version一致。只通过内置版本号比较是否为同一个profile包，不涉及协同版本号
            if (config == null) {
                log.info("当前项目中不存在{}扩展包", it.getProfileName());
                return true;
            }

            if (it.getDbVersion() != null && it.getRegTime() != null) {
                ProfileMessage message = new ProfileMessage();
                message.setVersion(it.getDbVersion());
                message.setRegTime(it.getRegTime());
                boolean result = isImportProfile(message, config);
                if (result) {
                    log.info("{}内置版本发生变更, profileId:{}, newDbVersion:{}, oldDbVersion:{}, newRegTime:{}, oldRegTime:{}",
                            it.getProfileName(),
                            it.getRootModel(),
                            it.getDbVersion(),
                            config.getVersion(), it.getRegTime(), config.getRegTime());
                }

                return result;
            }

            return false;
        }).collect(Collectors.toList());

        for (ProfileConfigVo profile : finalDep) {
            try {
                internalProjectService.setGlobalWriteableState(project.getId(), true);
                if (Objects.equals(profile.getDataType(), ProjectDataTypeEnum.DB.value())) {
                    String depPath = profile.getPath();
                    String dbPath = projectManager.extractProfileDb(depPath, project, profile.getRootModel(), project.getDefaultSaveDir());
                    if (dbPath == null) {
                        throw AbortExecutionException.build(ErrorCode.EXTRACT_DB_FILE_ERROR);
                    }
                    String currentId = project.getCurrentId();
                    ProfileMessage message = new ProfileMessage();
                    message.setVersion(profile.getDbVersion());
                    message.setRegTime(profile.getRegTime());

                    ProfileChange profileChange = internalUmlService.importProfileFromDbToFacility(project.getId(),
                            dbPath,
                            profile.getRootModel(), message);
                    Files.deleteIfExists(Paths.get(project.getDefaultSaveDir(),
                            currentId + "_" + project.getId() + "_" + profile.getRootModel(), "mofFiles/mofModel", String.format("%s.db", "mofProject")));
                    Files.deleteIfExists(Paths.get(project.getDefaultSaveDir(), currentId + "_" + project.getId() + "_" + profile.getRootModel(), "mofFiles/mofModel"));
                    Files.deleteIfExists(Paths.get(project.getDefaultSaveDir(), currentId + "_" + project.getId() + "_" + profile.getRootModel(), "mofFiles"));
                    Files.deleteIfExists(Paths.get(project.getDefaultSaveDir(), currentId + "_" + project.getId() + "_" + profile.getRootModel()));
                    fillProfileChange(project, profileChange);
                } else {
                    internalUmlService.importProfileFromJsonToFacility(project.getId(), profile.getModelData(), profile.getRootModel(), "");
                }
            } catch (IOException e) {
                log.error("profile文件删除失败");
                throw AbortExecutionException.build(ErrorCode.PROFILE_IMPORT_ERROR, e);
            } catch (Exception e) {
                log.error("importProfileFromDbToFacility失败,projectId:{}, profileName:{}, version:{}, dbVersion:{}, " +
                                "path:{}, " +
                                "regTime:{}",
                        project.getId(),
                        profile.getProfileName(),
                        profile.getProfileVersion(), profile.getDbVersion(), profile.getPath(), profile.getRegTime());
                throw AbortExecutionException.build(ErrorCode.PROFILE_IMPORT_ERROR, e);
            } finally {
                internalProjectService.setGlobalWriteableState(project.getId(), false);
            }

        }
        return finalDep.stream().map(ProfileConfigVo::getRootModel).collect(Collectors.toSet());
    }

    private static boolean isImportProfile(ProfileMessage message, ProfileConfig config) {
        LogUtil.printSerializeOnlineLogs("message: {}, config: {}", message, config);
        //得到当前拓展包数据版本 profileConfig Version
        //当多机器导出时 version可能一致，通过时间进行判断是否一致。
        if (config == null || config.getVersion() != message.getVersion()
        ) {
            return true;
        } else {
            return !message.getRegTime().equals(config.getRegTime());
        }
    }

    /**
     * 初始化用户自定义profile
     *
     * @param dependencies
     * @param path
     * @param initProfile
     * @param project
     * @return
     */
    @NotNull
    public Set<String> initProfileDependency(
            final List<ModelDependency> dependencies,
            final String path,
            final List<ModelDependency> initProfile,
            final String localPath,
            final Project project) {
        LogUtil.printSerializeOnlineLogs("dependencies: {}, path: {}, initProfile: {}, localPath: {}, project: {}",
                dependencies, path, initProfile, localPath, project);
        //get all dependency, by bfs.
        Set<String> visited = new HashSet<>();
        //init项目的依赖，不考虑，设置为已访问
        List<ModelDependency> myDependencies = dependencies.stream().filter(it -> initProfile.stream().noneMatch(profile ->
                StringUtils.equals(profile.getProfileName(), it.getProfileName())
        )).collect(Collectors.toList());

        myDependencies.forEach(p -> visited.add(p.getProfileName()));
        //init项目的依赖，不考虑，设置为已访问
        initProfile.forEach(p -> visited.add(p.getProfileName()));
        Queue<ModelDependency> queue = new LinkedList<>(myDependencies);
        List<ProfileConfigVo> finalDep = new ArrayList<>();

        while (!queue.isEmpty()) {
            ModelDependency c = queue.poll();
            String depPath;
            if (Objects.equals(c.getProfileName(), ProfileConstants.DIAGRAM_CONFIGURATION) ||
                    Objects.equals(c.getProfileName(), ProfileConstants.TRACEABILITY_CUSTOMIZATION) ||
                    Objects.equals(c.getProfileName(), UAFProfileConstants.ARCH_CONFIGURATION) ||
                    Objects.equals(c.getProfileName(), UAFProfileConstants.SOS_201) ||
                    Objects.equals(c.getProfileName(), UAFProfileConstants.CASIC3) ||
                    Objects.equals(c.getProfileName(), UAFProfileConstants.VIRE) ||
                    Objects.equals(c.getProfileName(), UAFProfileConstants.HGS18) ||
                    Objects.equals(c.getProfileName(), ProfileConstants.EXTERNAL_INTEGRATION) ||
                    Objects.equals(c.getProfileName(), ProfileConstants.ARCH_VALIDATION_PROFILE) ||
                    Objects.equals(c.getProfileName(), ProfileConstants.DESIGN_VALIDATION_PROFILE) ||
                    Objects.equals(c.getProfileName(), ProfileConstants.AN_SHI_YA_TAI_DEFAULT_DATA_MAPPING_CONFIGURATION) ||
                    Objects.equals(c.getProfileName(), ProfileConstants.DIAGRAM_TABLE_COLUMN_RENAME_CONFIGURATION) ||
                    Objects.equals(c.getProfileName(), ProfileConstants.SHANG_FEI_CONFIGURATION)) {
                depPath = getProfileFilePath(localPath, c.getProfileName(), c.getProfileVersion());
                log.info("des path:{}", depPath);
            } else {
                depPath = getProfileFilePath(path, c.getProfileName(), c.getProfileVersion());
            }

            ReadMd3Utils.MD3FileInfo md3pInfo = ReadMd3Utils.unZip(depPath);
            final ProfileConfigVo profile;
            final ProfileMessage profileMessage;
            try {
                profile = new ObjectMapper().readValue(md3pInfo.readMofProject(), ProfileConfigVo.class);
                final String profileConfig = md3pInfo.readProfileConfig();
                if (profileConfig != null) {
                    profileMessage = new ObjectMapper().readValue(profileConfig, ProfileMessage.class);
                    profile.setDbVersion(profileMessage.getVersion());
                    profile.setRegTime(profileMessage.getRegTime());
                }
            } catch (Exception e) {
                log.error("profileMessage:{}", md3pInfo.readProfileConfig());
                log.error("profile:{}", md3pInfo.readMofProject());
                throw AbortExecutionException.build(ErrorCode.PROJECT_DATA_READ_ERROR, e);
            }

            profile.setPath(depPath);
            profile.setProfileVersion(c.getProfileVersion());
            profile.setProfileName(c.getProfileName());
            finalDep.add(profile);
            final List<ModelDependency> newDependencies = profile.getDependencies();
            for (ModelDependency newDep : newDependencies) {
                if (!visited.contains(newDep.getProfileName())) {
                    visited.add(newDep.getProfileName());
                    queue.offer(newDep);
                }
            }
        }
        return initProfile(project, finalDep);
    }

    private void fillProfileChange(Project project, ProfileChange profileChange) {
        LogUtil.printSerializeOnlineLogs("project: {}, profileChange: {}", project, profileChange);
        if (CollectionUtils.isNotEmpty(profileChange.getImageIds())) {
            final List<String> keys = Stream.of(UMLDefinitionConstants.A_icon_stereotype_stereotype).collect(Collectors.toList());
            final Map<MetaClassInstance, List<String>> queryMap = internalUmlService.fetchInstanceByIds(
                    new ArrayList<>(profileChange.getImageIds()), project.getId()).stream().collect(Collectors.toMap(a -> a, b -> keys));

            Set<String> stereotypes = internalUmlService.queryPropertyByModelKeyMap(project.getId(),
                            queryMap).getMofPropertyInfoMap().values().stream()
                    .map(info -> info.get(UMLDefinitionConstants.A_icon_stereotype_stereotype).getValues())
                    .filter(Objects::nonNull)
                    .map(MetaClassInstance.class::cast)
                    .map(BasicRElement::getId)
                    .collect(Collectors.toSet());
            project.getProfileChange().addStereotypes(stereotypes);
        }

        project.getProfileChange().addStereotypes(profileChange.getUpdateStereotypeIds());
        project.getProfileChange().addDeleteStereotypes(profileChange.getDeleteStereotypeIds());
    }

    @NotNull
    public CopyResultVo importPackage(final String projectId, final String rootId, final String path) {
        LogUtil.printOnlineLogs("projectId: {}, rootId: {}, path: {}", projectId, rootId, path);
        final Project project = projectManager.getProject(projectId);
        if (Objects.isNull(project)) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_NOT_FOUND);
        }
        CopyResultVo modelResultVo = new CopyResultVo();
        LocalTransaction transaction = transactionService.createTransaction(projectId, ADD_MODEL);
        final MetaClassInstance rootInstance = internalUmlService.fetchInstance(rootId, projectId);
        if (Objects.isNull(rootInstance)
                || (!internalUmlService.checkInstanceType(projectId, rootInstance, UMLDefinitionConstants.Package)
                && !internalUmlService.checkInstanceType(projectId, rootInstance, UMLDefinitionConstants.Model))) {
            log.warn("项目的导入路径节点应该在包模型下或根节点模型下!");
            throw AbortExecutionException.build(ErrorCode.PARAM_ERROR);
        }
        try {
            ReadMd3Utils.MD3FileInfo md3Info = ReadMd3Utils.unZip(path);
            final String projectData = md3Info.readMofProject();
            if (StringUtils.isEmpty(projectData)) {
                throw AbortExecutionException.build(ErrorCode.PROJECT_DATA_READ_ERROR);
            }
            final ProjectVo profile = new ObjectMapper().readValue(md3Info.readMofProject(), ProjectVo.class);
            String dbPath = projectManager.extractProfileDb(path, project, profile.getRootModel(), project.getDefaultSaveDir());
            if (dbPath == null) {
                throw AbortExecutionException.build(ErrorCode.EXTRACT_DB_FILE_ERROR);
            }
            ImportPackageResult result = persistenceBaseService.importPackageFromDbToFacility(projectId, dbPath, rootId, profile.getRootModel());
            transactionService.commit(projectId);
            InstanceVoUtils.fillImportResultVo(modelResultVo, transaction, result);
            if (checkIsLoadPrivateData(projectId, result.getInstanceMap().values())) {
                this.initializeService.initialize(projectId, false, false, true, project.getProjectSpecification());
            }
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.ADD_MODEL_ERROR, e);
        }

        return modelResultVo;
    }

    private boolean checkIsLoadPrivateData(String projectId, Collection<MetaClassInstance> values) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, values: {}", projectId, values);
        for (MetaClassInstance value : values) {
            if (internalUmlService.checkInstanceType(projectId, value, UMLDefinitionConstants.Stereotype)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据导入的profile路径，生成项目需要的依赖
     *
     * @param projectId
     * @param profilePath
     * @return java.util.List<com.huawang.mdesign.model.service.model.project.ModelDependency>
     * @author xz
     * @date 2023/05/25 09:37
     */
    @NotNull
    public List<ModelDependency> createDependencyByNewProfile(final String projectId, final String profilePath) {
        LogUtil.printOnlineLogs("projectId: {}, profilePath: {}", projectId, profilePath);
        final Project project = projectManager.getProject(projectId);
        if (Objects.isNull(project)) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_NOT_FOUND);
        }
        ReadMd3Utils.MD3FileInfo md3pInfo = ReadMd3Utils.unZip(profilePath);
        final String projectData = md3pInfo.readMofProject();
        if (StringUtils.isEmpty(projectData)) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_DATA_READ_ERROR);
        }
        final ProjectConfig config = md3pInfo.readConfig();
        final List<ModelDependency> dependencies = project.getDependencies();
        if (Objects.nonNull(config) && Objects.nonNull(config.getProfileName())
                && Objects.nonNull(config.getProfileVersion())) {
            if (dependencies.stream().anyMatch(it -> StringUtils.equals(it.getProfileName(), config.getProfileName()))) {
                throw AbortExecutionException.build(ErrorCode.PROFILE_IS_IMPORTED);
            }
            dependencies.add(new ModelDependency(config.getProfileName(), config.getProfileVersion()));
        }
        return dependencies;
    }

    @NotNull
    public List<CheckProfileExportVo> checkProfileExport(ProfileExportDTO profileExportDto) {
        LogUtil.printSerializeOnlineLogs("profileExportDto: {}", profileExportDto);
        final String projectId = profileExportDto.getProjectId();
        final Project curProject = projectManager.getProject(projectId);
        if (Objects.isNull(curProject)) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_NOT_FOUND);
        }

        final MetaClassInstance classInstance = internalUmlService.fetchInstance(profileExportDto.getInstanceId(),
                projectId);
        if (Objects.isNull(classInstance)
                || !internalUmlService.checkInstanceType(projectId, classInstance, UMLDefinitionConstants.Package)) {
            log.warn("对应的项目的导出模型不是package其中profileId是: {}， 以及projectId是: {}", profileExportDto.getInstanceId(), projectId);
            throw AbortExecutionException.build(ErrorCode.PARAM_ERROR);
        }

        ExportOutsideElementInfo result = persistenceBaseService.findOutsideElement(projectId,
                profileExportDto.getInstanceId(), false);
        return result.getOtherOutsideInstanceIds().stream().map(it -> {
            CheckProfileExportVo vo = new CheckProfileExportVo();
            vo.setInstanceId(it.getElementId());
            vo.setPropertyKey(it.getDependProperty());
            vo.setRelationKey(it.getDependRelationId());
            vo.setDependInstanceId(it.getDependElementId());
            return vo;
        }).collect(Collectors.toList());
    }

    @NotNull
    public Project exportProfile(final String projectId, final String profileId,
                                 final String instanceId,
                                 String dataType, Boolean isPackageExport) {
        LogUtil.printOnlineLogs("projectId: {}, profileId: {}, instanceId: {}, dataType: {}, isPackageExport: {}", projectId,
                profileId, instanceId, dataType, isPackageExport);

        ExportProjectDTO exportProjectDTO = getExportProjectDTO(projectId, instanceId, dataType, isPackageExport);
        final Project curProject = exportProjectDTO.getProject();
        final MetaClassInstance classInstance = exportProjectDTO.getClassInstance();
        String tempFilePath = exportProjectDTO.getTempFilePath();
        ExportOutsideElementResult exportOutsideElementResult = exportProjectDTO.getExportOutsideElementResult();

        final Project profile = new Project();
        profile.setExport(true);
        profile.setRootModel(Objects.isNull(exportOutsideElementResult) ? instanceId : exportOutsideElementResult.getModelId());
        try {
            profile.setModel(persistenceBaseService.exportPackagesToJsonStringNoPretty(projectId, classInstance.getId(),
                    dataType));
        } catch (IsOutSideException e) {
            OutSideTip sideTip = tipService.getOutSideTip(projectId, e.getOutsideInstances());
            throw AbortExecutionException.buildByMessage(sideTip.buildTip(), e);
        }
        profile.setId(profileId);
        profile.setDependencies(curProject.getDependencies());
        profile.setDataType(dataType);
        if (!"".equals(tempFilePath)) {
            profile.setTmpFilePath(tempFilePath);
        }
        return profile;
    }

    public DistributeProjectVo distributeExportProfile(final String projectId,
                                                       final String instanceId,
                                                       String dataType, Boolean isPackageExport) {
        ExportProjectDTO exportProjectDTO = getExportProjectDTO(projectId, instanceId, dataType, isPackageExport);
        final Project curProject = exportProjectDTO.getProject();
        String tempFilePath = exportProjectDTO.getTempFilePath();
        ExportOutsideElementResult exportOutsideElementResult = exportProjectDTO.getExportOutsideElementResult();

        final DistributeProjectVo distributeProjectVo = new DistributeProjectVo();
        distributeProjectVo.setProjectId(projectId);
        distributeProjectVo.setExport(true);
        distributeProjectVo.setRootModel(Objects.isNull(exportOutsideElementResult) ? instanceId : exportOutsideElementResult.getModelId());
        distributeProjectVo.setDataType(dataType);
        distributeProjectVo.setTempFilePath(tempFilePath);
        distributeProjectVo.setDependencies(curProject.getDependencies());
        // 设置delete和modify
        if (Objects.nonNull(exportOutsideElementResult)) {
            distributeProjectVo.setDeleteModel(exportOutsideElementResult.getDelModelIds());
            distributeProjectVo.setModifyModel(exportOutsideElementResult.getUpdateModelIds());
        }
        return distributeProjectVo;
    }

    private ExportProjectDTO getExportProjectDTO(final String projectId,
                                                 final String instanceId, String dataType, Boolean isPackageExport) {
        final Project curProject = projectManager.getProject(projectId);
        if (Objects.isNull(curProject)) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_NOT_FOUND);
        }

        final MetaClassInstance classInstance = internalUmlService.fetchInstance(instanceId, projectId);
        if (Objects.isNull(classInstance)
                || !internalUmlService.checkInstanceType(projectId, classInstance, UMLDefinitionConstants.Package)) {
            log.warn("对应的项目的导出模型不是profile其中profileId是: {}, 以及projectId是: {}", instanceId, projectId);
            throw AbortExecutionException.build(ErrorCode.PARAM_ERROR);
        }
        String tempFilePath = "";
        ExportOutsideElementResult exportOutsideElementResult = null;
        if (ProjectDataTypeEnum.DB.value().equals(dataType)) {
            exportOutsideElementResult = getExportOutsideElementResult(projectId, instanceId, isPackageExport, curProject);
            tempFilePath = getTempFilePath(projectId, instanceId);
        }

        ExportProjectDTO exportProjectDTO = new ExportProjectDTO();
        exportProjectDTO.setProject(curProject);
        exportProjectDTO.setClassInstance(classInstance);
        exportProjectDTO.setTempFilePath(tempFilePath);
        exportProjectDTO.setExportOutsideElementResult(exportOutsideElementResult);
        return exportProjectDTO;
    }

    private String getTempFilePath(String projectId, String instanceId) {
        String tempFilePath;
        try {
            tempFilePath = internalProjectService.saveProfile(projectId, instanceId);
        } catch (IOException e) {
            throw AbortExecutionException.build(ErrorCode.EXPORT_PROFILE_ERROR, e);
        }
        return tempFilePath;
    }

    @NotNull
    private ExportOutsideElementResult getExportOutsideElementResult(String projectId, String instanceId, Boolean isPackageExport, Project curProject) {
        ExportOutsideElementResult exportOutsideElementResult;
        try {
            String profilePath = projectManager.createProfileEmptyDb(projectId, instanceId, curProject.getDefaultSaveDir());
            projectManager.flushDb(projectId);
            exportOutsideElementResult = persistenceBaseService.exportProfileDataToDb(projectId, instanceId, profilePath, !isPackageExport);
        } catch (IOException e) {
            throw AbortExecutionException.build(ErrorCode.CREATE_PROFILE_DB_ERROR, e);
        }
        return exportOutsideElementResult;
    }

    @Nullable
    @Transactional
    public Project download(final String projectId, final Boolean isCoWork) {
        LogUtil.printOnlineLogs("projectId: {}, isCoWork: {}", projectId, isCoWork);
        final Project project = projectManager.getValidProject(projectId);
        try {
            projectManager.flushDb(projectId);
            Path path = getTmpFolderByTime();
            //确保项目切换后上下文一并切换过来。
            internalUmlService.fetchInstance(UMLDefinitionConstants.Package, project.getId());
            if (isCoWork != null && (isCoWork || project.isOnline())) {
                persistenceBaseService.updateStructSlotModelCreatorTypeIsNull(projectId);
            }
            internalProjectService.saveModel(project, path);
            project.setDataType(ProjectDataTypeEnum.DB.value());
            project.setTmpFilePath(path.toAbsolutePath().toString());
        } catch (IOException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_DOWNLOAD_ERROR, e);
        }

        project.setExport(false);
        return project;
    }

    @Nullable
    public Project downloadOffline(final String projectId, final String newProjectId) {
        LogUtil.printOnlineLogs("projectId: {}, newProjectId: {}", projectId, newProjectId);
        final Project project = projectManager.getValidProject(projectId);
        try {
            projectManager.flushDb(projectId);
            Path path = getTmpFolderByTime();
            //确保项目切换后上下文一并切换过来。
            internalUmlService.fetchInstance(UMLDefinitionConstants.Package, project.getId());
            umlFacility.updateStructSlotModelCreatorTypeIsNull(projectId);
            String newDbDir = internalProjectService.saveModel(project, path);
            internalProjectService.setProjectReadOnly(projectId, newDbDir);
            internalProjectService.coworkUpdateUseProject(projectId, newDbDir, projectId, newProjectId);
            project.setDataType(ProjectDataTypeEnum.DB.value());
            project.setTmpFilePath(path.toAbsolutePath().toString());
        } catch (IOException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_DOWNLOAD_ERROR, e);
        }

        project.setExport(false);
        return project;
    }

    @NotNull
    public ModelResultVo undo(@NotNull String projectId, @NotNull String transactionId) {
        LogUtil.printOnlineLogs("projectId: {}, transactionId: {}", projectId, transactionId);
        ExecutingRecordResult transactionList = transactionService.undo(projectId, transactionId);
        ModelResultVo modelResultVo = new ModelResultVo();
        fillUndoRedoModelResultVo(modelResultVo, transactionList);
        return modelResultVo;
    }

    @NotNull
    public ModelResultVo redo(@NotNull String projectId, @NotNull String transactionId) {
        LogUtil.printOnlineLogs("projectId: {}, transactionId: {}", projectId, transactionId);
        ExecutingRecordResult transactionList = transactionService.redo(projectId, transactionId);
        ModelResultVo modelResultVo = new ModelResultVo();
        fillUndoRedoModelResultVo(modelResultVo, transactionList);
        return modelResultVo;
    }


    @NotNull
    public List<String> list() {
        return projectManager.projectList();
    }

    /**
     * 导入reqIf格式的需求表
     *
     * @param dto
     * @return com.huawang.mdesign.model.service.vo.ModelResultVo
     * @author xz
     * @date 2023/05/25 10:12
     */
    @NotNull
    public ModelResultVo importReqIf(final ImportDTO dto) {
        LogUtil.printSerializeOnlineLogs("importReqIf -> dto: ", dto);
        final String projectId = dto.getProjectId();
        final String parentId = dto.getParentId();
        return importHandler.importReqIfIntoProjectByBatch(dto.getFilePath(), projectId, parentId);
    }

    @NotNull
    public List<ReqIfPreviewVo> previewReqif(final ImportReqIfDTO dto) {
        LogUtil.printSerializeOnlineLogs("dto: ", dto);
        final String projectId = dto.getProjectId();
        return importHandler.parseReqIfAll(dto.getFilePath(), projectId);
    }

    @NotNull
    public ModelResultVo importReqIfV2(final ImportReqIfDTO dto) {
        LogUtil.printSerializeOnlineLogs("dto: ", dto);
        final String projectId = dto.getProjectId();
        final ReqIfDataInfo reqIfDataInfo = ReqIfDataInfo.builder()
                .projectId(projectId)
                .stereotypes(dto.getStereotypes())
                .parentId(dto.getParentId())
                .attributesMap(dto.getAttributesMap())
                .relationsMap(dto.getRelationsMap())
                .needAddDiagram(dto.isNeedAddDiagram())
                .isCoverUpdate(dto.isCoverUpdate())
                .build();
        return importHandler.importReqIfIntoProjectByBatchV2(reqIfDataInfo, dto.getFilePath());
    }

    /**
     * 导入excel格式的需求表
     *
     * @param dto
     * @return com.huawang.mdesign.model.service.vo.ModelResultVo
     * @author xz
     * @date 2023/05/25 10:13
     */
    @NotNull
    public ModelResultVo importExcel(final ImportDTO dto) {
        LogUtil.printSerializeOnlineLogs("importExcel -> dto: ", dto);
        final String projectId = dto.getProjectId();
        final String parentId = dto.getParentId();

        try {
            return importHandler.importExcelIntoProjectByBatch(projectId, parentId, dto.getFilePath());
        } catch (Exception e) {
            throw AbortExecutionException.build(ErrorCode.SERVICE_ERROR, e);
        }
    }

    @Nullable
    public ProjectVo makeVo(final Project project) {
        LogUtil.printSerializeOnlineLogs("project: {}", project);
        if (project == null) {
            return null;
        }

        ProjectVo projectVo = new ProjectVo();
        projectVo.setProjectId(project.getId());
        projectVo.setModelData(project.getModel());
        project.setModel(null);
        projectVo.setDependencies(project.getDependencies());
        projectVo.setRootModel(project.getRootModel());
        projectVo.setExport(project.isExport());
        projectVo.setProjectType(project.getProjectType());
        projectVo.setTempFilePath(project.getTmpFilePath());
        projectVo.setDataType(project.getDataType());
        if (project.getProfileChange() != null) {
            projectVo.setUpdateStereotypeIds(new ArrayList<>(project.getProfileChange().getStereotypeIds()));
            projectVo.setDeleteStereotypeIds(new ArrayList<>(project.getProfileChange().getDeleteStereotypeIds()));
        }
        projectVo.setDbDir(project.getDbUrl());
        projectVo.setTemplateIdMap(project.getTemplateIdMap());
        return projectVo;
    }

    @Nullable
    public ProjectIncludeProfileVo makeProjectIncludeProfileVo(String projectId) {
        LogUtil.printOnlineLogs("makeProjectIncludeProfileVo -> projectId: ", projectId);
        ProjectIncludeProfileVo projectIncludeProfileVo = new ProjectIncludeProfileVo();
        Project project = download(projectId, false);
        if (Objects.isNull(project)) {
            return null;
        }
        projectIncludeProfileVo.setProjectId(project.getId());
        projectIncludeProfileVo.setModelData(project.getModel());
        project.setModel(null);
        projectIncludeProfileVo.setDependencies(project.getDependencies());
        projectIncludeProfileVo.setRootModel(project.getRootModel());
        projectIncludeProfileVo.setExport(project.isExport());
        projectIncludeProfileVo.setProjectType(project.getProjectType());
        projectIncludeProfileVo.setTempFilePath(project.getTmpFilePath());
        projectIncludeProfileVo.setProfileLibPath(project.getProfileLibPath());
        projectIncludeProfileVo.setDefaultProfiles(ProfileConstants.DEFAULT_PROFILE);
        return projectIncludeProfileVo;
    }

    private final Object lock = new Object();

    public void init() {
        synchronized (lock) {
            initializeService.initialize(DefinitionStoreRepository.DEFAULT_SYSML_PROJECT_ID,
                    com.huawang.business.constants.ProjectSpecificationEnum.SYSML.value());
        }
    }

    public void clearVariation(String projectId) {
        LogUtil.printOnlineLogs("clearVariation -> projectId: ", projectId);
        internalProjectService.clearVariation(projectId);
    }

    public ModelResultVo mergeVariationToLocal(MergeVariationDTO dto) {
        final String projectId = dto.getProjectId();
        Project project = projectManager.getValidProject(projectId);
        List<MofModelVariation> variationList = internalProjectService.mergeVariationToLocal(dto);
        ModelResultVo modelResultVo = new ModelResultVo();
        LocalTransaction localTransaction = transactionService.createTransaction(projectId, MERGE_MODEL_TO_LOCAL);
        Set<String> addObjects;
        try {
            internalProjectService.setGlobalWriteableState(projectId, true);
            addObjects = umlFacility.fModifyMofModelDataFromVariationClient(projectId, variationList);
            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            transactionService.commit(projectId);
            InstanceVoUtils.fillModelResultVo(modelResultVo, localTransaction);
            addObjects.addAll(modelResultVo.getAddModel());
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, localTransaction);
            throw AbortExecutionException.build(ErrorCode.COLWORK_PROJECT_MERGE_ERROR, e);
        } finally {
            internalProjectService.setGlobalWriteableState(projectId, false);
        }

        addModelHandler(projectId, addObjects);
        return modelResultVo;
    }

    /**
     * 协同增量新增模型处理
     *
     * @param projectId
     * @param addModelIds
     * @return void
     * @author xz
     * @date 2023/05/29 12:14
     */
    private void addModelHandler(String projectId, Set<String> addModelIds) {
        LogUtil.printOnlineLogs("projectId: {}, addModelIds: {}", projectId, addModelIds);
        if (CollectionUtils.isEmpty(addModelIds)) {
            return;
        }

        try {
            List<String> addModelIdList = new ArrayList<>(addModelIds);
            List<MetaClassInstance> addModels = internalUmlService.fetchInstanceByIds(addModelIdList, projectId);
            List<String> ownerIds = addModels.stream().map(MetaClassInstance::getOwnerId).collect(Collectors.toList());
            List<MetaClassInstance> owners = new ArrayList<>(internalUmlService.fetchInstanceByIds(ownerIds, projectId));
            final Map<String, Boolean> readOnlyMap = this.businessJudgeService.isReadOnly(projectId, owners);
            List<MetaClassInstance> writeOwner = owners.stream()
                    .filter(it -> !readOnlyMap.getOrDefault(it.getId(), false))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(writeOwner)) {
                Map<String, MetaClassInstanceTreeNode> tree = queryAddTree(addModels, owners);
                List<String> writeModels = writeOwner.stream().filter(it -> tree.containsKey(it.getId()))
                        .flatMap(owner -> queryMetaClassInstanceTreeChildren(tree.get(owner.getId())).stream())
                        .map(BasicRElement::getId)
                        .collect(Collectors.toList());
                internalUmlService.setIsNotReadOnly(projectId, writeModels);
            }
            final List<String> packages = addModels.stream().filter(it ->
                            internalUmlService.checkInstanceType(projectId, it, UMLDefinitionConstants.Package))
                    .map(MetaClassInstance::getId).collect(Collectors.toList());
            internalUmlService.setIsReadOnly(projectId, packages);
        } catch (Exception e) {
            log.error("元素只读状态更新失败", e);
        }

    }

    @NotNull
    public List<MetaClassInstance> queryMetaClassInstanceTreeChildren(@NotNull MetaClassInstanceTreeNode tree) {
        LogUtil.printSerializeOnlineLogs("tree: ", tree);
        List<MetaClassInstance> result = tree.getChildren().stream().map(MetaClassInstanceTreeNode::getInstance)
                .collect(Collectors.toList());
        tree.getChildren().forEach(child -> result.addAll(queryMetaClassInstanceTreeChildren(child)));
        return result;
    }

    /**
     * 查询新增模型树
     *
     * @param instances
     * @param owners
     * @return java.util.Map<java.lang.String, com.huawang.mdesign.model.service.facade.dto.MetaClassInstanceTree>
     * @author xz
     * @date 2023/05/29 12:12
     */
    @NotNull
    private Map<String, MetaClassInstanceTreeNode> queryAddTree(List<MetaClassInstance> instances,
                                                                List<MetaClassInstance> owners) {
        LogUtil.printSerializeOnlineLogs("instances: {}, owners: {}", instances, owners);
        Map<String, MetaClassInstanceTreeNode> tree = new HashMap<>();
        Map<String, MetaClassInstanceTreeNode> nodeMap = instances.stream().map(this::createMetaClassInstanceTreeNode)
                .collect(Collectors.toMap(k -> k.getInstance().getId(), k -> k));
        Map<String, MetaClassInstance> ownerMap = owners.stream().collect(Collectors.toMap(BasicRElement::getId, k -> k, (a, b) -> b));
        nodeMap.forEach((key1, value) -> {
            MetaClassInstance instance = value.getInstance();
            if (nodeMap.containsKey(instance.getOwnerId())) {
                nodeMap.get(instance.getOwnerId()).getChildren().add(value);
            } else {
                MetaClassInstanceTreeNode treeNode = tree.computeIfAbsent(instance.getOwnerId(), key ->
                        createMetaClassInstanceTreeNode(ownerMap.get(key)));
                treeNode.getChildren().add(value);
            }
        });
        return tree;
    }

    /**
     * 创建新增模型树节点
     *
     * @param instance
     * @return com.huawang.mdesign.model.service.facade.dto.MetaClassInstanceTree
     * @author xz
     * @date 2023/05/29 12:13
     */
    @NotNull
    public MetaClassInstanceTreeNode createMetaClassInstanceTreeNode(MetaClassInstance instance) {
        LogUtil.printOnlineLogs("instance: ", instance);
        MetaClassInstanceTreeNode treeNode = new MetaClassInstanceTreeNode();
        treeNode.setInstance(instance);
        return treeNode;
    }

    public void combineVariationIntoNowVariationList(MergeVariationDTO mergeVariationDto) {
        LogUtil.printOnlineLogs("mergeVariationDto: ", mergeVariationDto);
        final String projectId = mergeVariationDto.getProjectId();
        try {
            umlFacility.combineVariationIntoNowVariationList(projectId, mergeVariationDto.getVariationFilePath());
        } catch (CommandException e) {
            throw AbortExecutionException.build(ErrorCode.COLWORK_PROJECT_MERGE_ERROR, e);
        }
    }

    /**
     * 获取缺失owner的模型id
     *
     * @param projectId
     * @return java.util.List<java.lang.String>
     * @author xz
     * @date 2023/10/09 15:56
     */
    @NotNull
    public List<String> getOwnerAbsentInstanceIds(String projectId) {
        LogUtil.printOnlineLogs("getOwnerAbsentInstanceIds -> projectId: ", projectId);
        Project project = projectManager.getValidProject(projectId);
        return umlFacility.getOwnerAbsentInstanceIds(projectId, project.getRootModel());
    }

    @NotNull
    public ModelOwnerFixVo modelOwnerIdFix(ModelFixDTO modelFixDto) {
        LogUtil.printSerializeOnlineLogs("modelFixDto: ", modelFixDto);
        final String projectId = modelFixDto.getProjectId();
        final Project project = projectManager.getValidProject(projectId);
        ModelOwnerFixVo modelOwnerFixVo = new ModelOwnerFixVo();
        LocalTransaction localTransaction = transactionService.createTransaction(projectId, MODEL_FIX);
        if (localTransaction == null) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR);
        }
        boolean isCoWork = project.isOnline();
        try {
            internalProjectService.setGlobalWriteableState(projectId, true);
            if (isCoWork) {
                this.iSaveStateService.setIsLoggingVariation(projectId, false);
            }

            // 将根节点过滤
            List<FixOwnerInstanceDTO> fixOwnerInstanceDTOs = modelFixDto.getFixOwnerList().stream().filter(fixDto ->
                            StringUtils.isNotEmpty(fixDto.getInstanceId()) && StringUtils.isNotEmpty(fixDto.getOwnerId()))
                    .collect(Collectors.toList());
            Map<String, String> fixOwnerMap = fixOwnerInstanceDTOs.stream().collect(Collectors.toMap(
                    FixOwnerInstanceDTO::getInstanceId,
                    FixOwnerInstanceDTO::getOwnerId, (k, v) -> k));
            List<ICommand> commands = convertAddDTOToCommand(modelFixDto.getAddModelDTOS());
            ModelFixResult modelOwnerFix = umlFacility.modelOwnerIdFix(modelFixDto.getProjectId(), project.getRootModel(), isCoWork, fixOwnerMap, commands);
            transactionService.commit(projectId);
            modelOwnerFixVo.setNotFindOwnerModel(modelOwnerFix.getNoOwnerInstanceIds());
            modelOwnerFixVo.setReadOnlyModel(modelOwnerFix.getFailInstanceIdsByReadOnly());
            modelOwnerFixVo.setMultiplicityUniqueModel(modelOwnerFix.getMultipleChildrenInstanceIds());
            modelOwnerFixVo.setOtherModel(modelOwnerFix.getFailInstanceIdsByOther());
            modelOwnerFixVo.setTransactionId(localTransaction.getId());
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            log.warn("模型修复出错");
            transactionService.rollBack(projectId, localTransaction);
            throw AbortExecutionException.build(ErrorCode.COLWORK_PROJECT_MERGE_ERROR, e);
        } finally {
            internalProjectService.setGlobalWriteableState(projectId, false);
            if (isCoWork) {
                this.iSaveStateService.setIsLoggingVariation(projectId, true);
            }
        }
        return modelOwnerFixVo;
    }

    @NotNull
    private List<ICommand> convertAddDTOToCommand(final List<AddModelDTO> dtos) {
        LogUtil.printSerializeOnlineLogs("dtos: ", dtos);
        return dtos.stream().map(parameter -> {
            List<String> stereotypeList = parameter.getApplyStereotypes();
            if (stereotypeList == null) {
                stereotypeList = new ArrayList<>();
            }

            if (CommandAddType.MODEL.getCode().equals(parameter.getType())) {
                return CommandFactory.createAddModelCommand(
                        parameter.getParentId(),
                        parameter.getMetaclass(),
                        parameter.getInstanceId(),
                        parameter.getDefaultName(),
                        stereotypeList);
            } else if (CommandAddType.RELATIONSHIP.getCode().equals(parameter.getType())) {
                return CommandFactory.createAddRelationCommand(parameter.getParentId(),
                        parameter.getMetaclass(),
                        parameter.getInstanceId(),
                        parameter.getDefaultName(),
                        parameter.getSource(),
                        parameter.getTarget(),
                        stereotypeList);
            } else {
                log.warn("CommandAddType错误：{}", parameter.getType());
            }

            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());

    }

    @NotNull
    public Project downloadDiff(String projectId) {
        LogUtil.printOnlineLogs("downloadDiff -> projectId: ", projectId);
        final Project project = projectManager.getValidProject(projectId);
        try {
            Path path = getTmpFolderByTime();
            //确保项目切换后上下文一并切换过来。
            internalUmlService.fetchInstance(UMLDefinitionConstants.Package, project.getId());
            internalProjectService.saveVariation(project, path);
            project.setDataType(ProjectDataTypeEnum.DB.value());
            project.setTmpFilePath(path.toAbsolutePath().toString());
        } catch (IOException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_DOWNLOAD_ERROR, e);
        }
        project.setExport(false);
        return project;
    }

    @Nullable
    public Project createTemplate(ProjectTemplateCreateDto dto) {
        LogUtil.printSerializeOnlineLogs("createTemplate -> dto: ", dto);
        ValidateDataUtil.isNotNull(dto.getDefaultSaveDir(), ErrorCode.DEFAULT_DIR_NULL);
        final String projectId = dto.getProjectId();
        Project project = projectManager.getProject(projectId);
        if (project != null) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_REPEAT);
        }
        List<String> oldProfile = new ArrayList<>(DEFAULT_PROFILE);
        ProjectUtils.updateProfileByProjectSpecification(dto.getProjectSpecification());
        ReadMd3Utils.MD3FileInfo md3pInfo = ReadMd3Utils.unZip(dto.getTemplatePath());
        try {
            String currentId = SnowflakeIdWorkerUtil.getId();
            final ProjectVo template = new ObjectMapper().readValue(md3pInfo.readMofProject(), ProjectVo.class);
            final ProjectConfig config = md3pInfo.readConfig();
            final List<ModelDependency> dependencies =
                    config.getDependencies().stream().map(it -> new ModelDependency(it.get("profileName"),
                                    Long.valueOf(it.get("profileVersion"))))
                            .collect(Collectors.toList());
            project = projectManager.createAndActive(projectId, dependencies, currentId,
                    dto.getDefaultSaveDir(), "", dto.getProjectSpecification());
            if (StringUtils.isNotEmpty(dto.getProjectType())) {
                project.setProjectType(dto.getProjectType());
            }
            if (StringUtils.isNotEmpty(dto.getProjectSpecification())) {
                project.setProjectSpecification(dto.getProjectSpecification());
            }

            final List<ModelDependency> initProfile = DEFAULT_PROFILE.stream().map(it ->
                    new ModelDependency(it, 1L)).collect(Collectors.toList());
            Set<String> profileIds = new HashSet<>(DEFAULT_PROFILE);
            this.internalProjectService.setGlobalWriteableState(projectId, true);
            profileIds.addAll(initProfileDependency(dependencies, dto.getProfileLibPath(), initProfile,
                    dto.getProfileLibPath(), project));
            project.setDependencies(dependencies);
            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            final MetaClassInstance rootModel = createRootModel(project);
            projectManager.flushDb(projectId);
            project.setRootModel(rootModel.getId());
            this.iSaveStateService.setIsCoWork(projectId, true);
            String dbPath = projectManager.extractProfileDb(dto.getTemplatePath(), project, rootModel.getId()
                    , project.getDefaultSaveDir());
            if (dbPath == null) {
                throw AbortExecutionException.build(ErrorCode.EXTRACT_DB_FILE_ERROR);
            }

            log.info("newRootId:{}, oldRootId:{}", project.getRootModel(), template.getRootModel());
            log.info("dependency:{}", dependencies);
            ImportPackageResult result = persistenceBaseService.importPackageFromDbToFacility(projectId,
                    dbPath, rootModel.getId(), template.getRootModel());
            modelLimitService.checkLimit(result.getInstanceMap().size());
            if (StringUtils.isNotBlank(result.getPackageName())) {
                umlService.updateModel(projectId, rootModel.getId(), UMLDefinitionConstants.NamedElement_name,
                        result.getPackageName());
            }
            this.initializeService.initialize(projectId, false, true, true, project.getProjectSpecification());
            internalProjectService.setProfileOwner(project, rootModel, new HashSet<>(profileIds));
            this.iSaveStateService.setIsLoggingVariation(projectId, true);
            List<CopyInfoVo> templateIdMap = result.getInstanceIdMap().entrySet().stream().map(it -> {
                CopyInfoVo copyInfoVo = new CopyInfoVo();
                copyInfoVo.setOldId(it.getKey());
                copyInfoVo.setNewId(it.getValue());
                return copyInfoVo;
            }).collect(Collectors.toList());
            CopyInfoVo rootVo = new CopyInfoVo();
            rootVo.setOldId(template.getRootModel());
            rootVo.setNewId(project.getRootModel());
            templateIdMap.add(rootVo);
            project.setTemplateIdMap(templateIdMap);
        } catch (CommandException | JsonProcessingException e) {
            ProjectUtils.rollBackDefaultProfile(oldProfile);
            log.error("模板项目创建失败");
            throw AbortExecutionException.build(ErrorCode.TEMPLATE_PROJECT_ERROR, e);
        } catch (Exception e) {
            ProjectUtils.rollBackDefaultProfile(oldProfile);
            throw AbortExecutionException.build(ErrorCode.TEMPLATE_PROJECT_ERROR, e);
        } finally {
            this.internalProjectService.setGlobalWriteableState(projectId, false);
        }

        return project;
    }

    public boolean isExistVariation(String projectId) {
        LogUtil.printOnlineLogs("isExistVariation -> projectId: ", projectId);
        return umlFacility.isExistVariationData(projectId);
    }

    public void fillUndoRedoModelResultVo(ModelResultVo modelResultVo, ExecutingRecordResult transactionList) {
        LogUtil.printSerializeOnlineLogs("modelResultVo: {}, transactionList: {}", modelResultVo, transactionList);
        Set<String> deleteModel = new HashSet<>(transactionList.getDeleteInstanceIds());
        Set<String> modifyModel = transactionList.getUpdatePropertyNames().values().stream().map(UpdatePropertyNames::getUpdateInstanceId).collect(Collectors.toSet());
        Set<String> addModel = new HashSet<>(transactionList.getAddInstanceIds());
        List<UpdatePropertyNames> modifyModelAndProperties = new ArrayList<>(transactionList.getUpdatePropertyNames().values());
        modifyModelAndProperties.removeIf(it -> deleteModel.contains(it.getUpdateInstanceId()));

        modelResultVo.setDeleteModel(deleteModel);
        modelResultVo.setAddModel(TransactionUtil.getDistinctNewObjectSet(addModel, deleteModel));
        modelResultVo.setModifyModel(getDistinctUpdateObjectSet(addModel, modifyModel, deleteModel));
        modelResultVo.setModifyModelAndProperties(modifyModelAndProperties);
        InstanceVoUtils.setModelChange(true);
    }

    @NotNull
    public Set<String> getDistinctUpdateObjectSet(@NotNull Set<String> newObjects, @NotNull Set<String> updateObjects, @NotNull Set<String> deleteObjects) {
        LogUtil.printSerializeOnlineLogs("newObjects: {}, updateObjects: {}, deleteObjects: {}", newObjects, updateObjects,
                deleteObjects);
        Set<String> result = new HashSet<>(updateObjects);
        result.removeAll(newObjects);
        result.removeAll(deleteObjects);
        return result;
    }

    public void exportXmi(ExportXmiDTO xmiDto) {
        LogUtil.printSerializeOnlineLogs("xmiDto: ", xmiDto);
        List<UseProject> useProjects = queryShareService.queryAllUseProjects(xmiDto.getProjectId());
        for (UseProject useProject : useProjects) {
            log.info("打开项目:" + useProject.getUsableProject().getProjectPath());
            ProjectOpenDTO projectOpenDTO = new ProjectOpenDTO();
            projectOpenDTO.setProjectId(useProject.getUsableProject().getProjectId());
            projectOpenDTO.setFilePath(useProject.getUsableProject().getProjectPath());
            projectOpenDTO.setProfileLibPath(xmiDto.getProfileLibPath());
            projectOpenDTO.setOnlineProfileLibPath(xmiDto.getOnlineProfileLibPath());
            projectOpenDTO.setSaveWay("md3");
            projectOpenDTO.setIsReconnect(false);
            projectOpenDTO.setDefaultSaveDir(xmiDto.getDefaultSaveDir());
            openMd3(projectOpenDTO);
        }
        exportService.exportXmi(xmiDto);
        for (UseProject useProject : useProjects) {
            log.info("关闭项目:" + useProject.getUsableProject().getProjectPath());
            delete(useProject.getUsableProject().getProjectId(), "md3");
        }
    }

    @Nullable
    public ProjectVariationVo downloadLocalAsCowork(String coworkProjectId, String localProjectId) {
        final Project project = projectManager.getProject(coworkProjectId);
        ValidateDataUtil.isNotNull(project, ErrorCode.PROJECT_NOT_FOUND);
        project.setExport(false);
        ProjectVo projectVo = makeVo(project);
        ProjectVariationVo projectVariationVo = BeanUtil.copyProperties(projectVo, ProjectVariationVo.class);
        try {
            projectManager.flushDb(coworkProjectId);
            Path path = Files.createTempDirectory(String.format("p%s", System.currentTimeMillis()));
            //确保项目切换后上下文一并切换过来。
            internalUmlService.fetchInstance(UMLDefinitionConstants.Package, project.getId());
            persistenceBaseService.updateStructSlotModelCreatorTypeIsNull(coworkProjectId);
            internalProjectService.saveModel(project, path);
            ModelVariationComparesDTO modelVariationComparesDTO = internalProjectService.saveVariationWithLocalProjectCompares(coworkProjectId, localProjectId, path);
            projectVariationVo.setAddModel(modelVariationComparesDTO.getAddInstanceVariations());
            projectVariationVo.setModifyModel(modelVariationComparesDTO.getUpdateInstanceVariations());
            projectVariationVo.setDeleteModel(modelVariationComparesDTO.getDeleteInstanceVariations());
            projectVariationVo.setDataType(ProjectDataTypeEnum.DB.value());
            projectVariationVo.setTempFilePath(path.toAbsolutePath().toString());
        } catch (Exception e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_DOWNLOAD_ERROR, e);
        }
        return projectVariationVo;
    }

    public void issueXmi(ExportXmiDTO xmiDto) {
        exportService.issueXmi(xmiDto);
    }

    public void exportStandardXml(ExportXmiDTO xmiDto) {
        exportService.exportEclipseUml(xmiDto);
    }

    /**
     * 根据时间戳获得临时目录
     *
     * @throws IOException
     */
    private static Path getTmpFolderByTime() throws IOException {
        Path path = Files.createTempDirectory(String.format("p%s", System.currentTimeMillis()));
        //linux系统需要设置读写权限
        if (System.getProperty("os.name").toLowerCase().contains("linux")) {
            Set<PosixFilePermission> perms = Files.getPosixFilePermissions(path);
            if (!perms.contains(PosixFilePermission.OWNER_READ) || !perms.contains(PosixFilePermission.OWNER_WRITE)) {
                perms = PosixFilePermissions.fromString("rw-rw-rw-");
                Files.setPosixFilePermissions(path, perms);
            }
        }
        return path;
    }
}


